package com.shop.util;

import org.hyperic.sigar.*;
import org.hyperic.sigar.util.PrintfFormat;
import org.springframework.util.StringUtils;

import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryUsage;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

public class SystemInfo {

    private Sigar sigar;

    private SigarProxy proxy;

    private StringBuffer info = new StringBuffer();

    private void sigarInit(boolean isProxy) {
        sigar = new Sigar();
        if (isProxy) {
            proxy = SigarProxyCache.newInstance(this.sigar);
        }
    }

    private void shutdown() {
        this.sigar.close();
    }

    public String getInfo() {
        return info.toString();
    }

    public void clearInfo() {
        if (!StringUtils.isEmpty(info)) {
            info.delete(0, info.length());
        }
    }

    private void println(String arg) {
//        info.append(arg).append("/n");
        System.out.println(arg);
    }

    public String sprintf(String format, Object[] items) {
        return new PrintfFormat(format).sprintf(items);
    }

    public void printf(String format, Object[] items) {
        println(sprintf(format, items));
    }

    /**
     * CPU资源信息
     */
    public void cpuInfo() {
        clearInfo();
        try {
            sigarInit(false);
            List<CpuInfo> infos = Arrays.asList(this.sigar.getCpuInfoList());
            List<CpuPerc> cpus = Arrays.asList(this.sigar.getCpuPercList());
            long cacheSize = 0;
            CpuInfo info = infos.get(0);
            cacheSize = info.getCacheSize();
            println("Vendor........." + info.getVendor()); //获得CPU的卖主
            println("Model.........." + info.getModel()); //获得CPU的类别
            println("Mhz............" + info.getMhz()); //CPU的总量MHz
            println("Total CPUs....." + info.getTotalCores());
            println("Physical CPUs.." + info.getTotalSockets());
            println("Cores per CPU.." + info.getCoresPerSocket());

            if (cacheSize != Sigar.FIELD_NOTIMPL) {
                println("Cache size...." + cacheSize); //缓冲存储器数量
            }
            println("");
            for (int i = 0; i < cpus.size(); i++) {
                println("CPU " + i + ".........");
                outputCpuPerc(cpus.get(i));
            }
            println("Totals........");
            outputCpuPerc(this.sigar.getCpuPerc());
        } catch (SigarException e) {
            e.printStackTrace();
        } finally {
            shutdown();
        }
    }

    private void outputCpuPerc(CpuPerc cpu) {
        println("User Time....." + CpuPerc.format(cpu.getUser())); //用户使用率
        println("Sys Time......" + CpuPerc.format(cpu.getSys())); //系统使用率
        println("Idle Time....." + CpuPerc.format(cpu.getIdle())); //当前空闲率
        println("Wait Time....." + CpuPerc.format(cpu.getWait())); //当前等待率
        println("Nice Time....." + CpuPerc.format(cpu.getNice()));
        println("Combined......" + CpuPerc.format(cpu.getCombined())); //总的使用率
        println("Irq Time......" + CpuPerc.format(cpu.getIrq()));
        if (SigarLoader.IS_LINUX) {
            println("SoftIrq Time.." + CpuPerc.format(cpu.getSoftIrq()));
            println("Stolen Time...." + CpuPerc.format(cpu.getStolen()));
        }
        println("");
    }

    private static Long format(long value) {
        return new Long(value / 1024);
    }

    //内存资源信息
    public void memInfo() throws SigarException {
        clearInfo();
        try {
            sigarInit(false);
            Mem mem = this.sigar.getMem(); //内存
            Swap swap = this.sigar.getSwap(); //交换区
            Object[] header = new Object[]{"total", "used", "free"};
            printf("s s s", header);
            Object[] memRow = new Object[]{
                    format(mem.getTotal()), //内存总量
                    format(mem.getUsed()), //当前内存使用量
                    format(mem.getFree()) //当前内存剩余量
            };
            printf("Mem: ldK ldK ldK", memRow);
            Object[] memPercent = new Object[3];
            memPercent[0] = "100%";
            double d = mem.getUsedPercent();
            d = ((int) (d * 100)) / 100;
            memPercent[1] = d + "%";
            d = mem.getFreePercent();
            d = ((int) (d * 100)) / 100;
            memPercent[2] = d + "%";
            printf("MemPer: ls ls ls", memPercent);

            Object[] swapRow = new Object[]{
                    format(swap.getTotal()), //交换区总量
                    format(swap.getUsed()), //当前交换区使用量
                    format(swap.getFree()) //当前交换区剩余量
            };
            printf("Swap: ldK ldK ldK", swapRow);
            printf("RAM: ldM", new Object[]{mem.getRam()});

        } catch (RuntimeException e) {
            e.printStackTrace();
        } finally {
            shutdown();
        }
    }

    // 操作系统信息
    //获取当前操作系统的名称
    public String getPlatformName() {
        String hostname = "";
        try {
            hostname = InetAddress.getLocalHost().getHostName();
        } catch (Exception exc) {
            sigarInit(false);
            try {
                hostname = sigar.getNetInfo().getHostName();
            } catch (SigarException e) {
                hostname = "localhost.unknown";
            } finally {
                shutdown();
            }
        }
        return hostname;
    }

    //获取当前操作系统的信息
    public void getOSInfo() {
        OperatingSystem OS = OperatingSystem.getInstance();
        // 操作系统内核类型
        System.out.println("OS.getArch() = " + OS.getArch());
        System.out.println("OS.getCpuEndian() = " + OS.getCpuEndian());
        System.out.println("OS.getDataModel() = " + OS.getDataModel());
        // 系统描述
        System.out.println("OS.getDescription() = " + OS.getDescription());
        System.out.println("OS.getMachine() = " + OS.getMachine());
        // 操作系统类型
        System.out.println("OS.getName() = " + OS.getName());
        System.out.println("OS.getPatchLevel() = " + OS.getPatchLevel());
        // 操作系统的卖主
        System.out.println("OS.getVendor() = " + OS.getVendor());
        // 卖主名称
        System.out.println("OS.getVendorCodeName() = " + OS.getVendorCodeName());
        // 操作系统名称
        System.out.println("OS.getVendorName() = " + OS.getVendorName());
        // 操作系统卖主类型
        System.out.println("OS.getVendorVersion() = " + OS.getVendorVersion());
        // 操作系统的版本号
        System.out.println("OS.getVersion() = " + OS.getVersion());
    }

    // 获取当前系统进程表中的用户信息
    public void getOSUserInfo() {
        try {
            sigarInit(false);
            org.hyperic.sigar.Who[] who = sigar.getWhoList();
            if (!StringUtils.isEmpty(who)&& who.length > 0) {
                for (int i = 0; i < who.length; i++) {
                    System.out.println("\n~~~~~~~~~" + String.valueOf(i)+ "~~~~~~~~~");
                    org.hyperic.sigar.Who _who = who[i];
                    System.out.println("getDevice() = " + _who.getDevice());
                    System.out.println("getHost() = " + _who.getHost());
                    System.out.println("getTime() = " + _who.getTime());
                    // 当前系统进程表中的用户名
                    System.out.println("getUser() = " + _who.getUser());
                }
            }
        } catch (SigarException e) {
            e.printStackTrace();
        }
    }

    //硬盘资源信息
    public void getFileSystemInfo() throws Exception {
        try {
            sigarInit(false);
            //通过sigar.getFileSystemList()来获得FileSystem列表对象
            FileSystem fslist[] = sigar.getFileSystemList();
            //String dir = System.getProperty("user.home");// 当前用户文件夹路径
            for (int i = 0; i < fslist.length; i++) {
                System.out.println("\n~~~~~~~~~~" + i + "~~~~~~~~~~");
                FileSystem fs = fslist[i];
                // 分区的盘符名称
                System.out.println("fs.getDevName() = " + fs.getDevName());
                // 分区的盘符名称
                System.out.println("fs.getDirName() = " + fs.getDirName());
                System.out.println("fs.getFlags() = " + fs.getFlags());//
                // 文件系统类型，比如 FAT32、NTFS
                System.out.println("fs.getSysTypeName() = " + fs.getSysTypeName());
                // 文件系统类型名，比如本地硬盘、光驱、网络文件系统等
                System.out.println("fs.getTypeName() = " + fs.getTypeName());
                // 文件系统类型
                System.out.println("fs.getType() = " + fs.getType());
                FileSystemUsage usage = null;
                try {
                    usage = sigar.getFileSystemUsage(fs.getDirName());
                } catch (SigarException e) {
                    if (fs.getType() == 2)
                        throw e;
                    continue;
                }
                switch (fs.getType()) {
                    case 0: // TYPE_UNKNOWN ：未知
                        break;
                    case 1: // TYPE_NONE
                        break;
                    case 2: // TYPE_LOCAL_DISK : 本地硬盘
                        // 文件系统总大小
                        System.out.println(" Total = " + usage.getTotal() + "KB");
                        // 文件系统剩余大小
                        System.out.println(" Free = " + usage.getFree() + "KB");
                        // 文件系统可用大小
                        System.out.println(" Avail = " + usage.getAvail() + "KB");
                        // 文件系统已经使用量
                        System.out.println(" Used = " + usage.getUsed() + "KB");
                        double usePercent = usage.getUsePercent() * 100D;
                        // 文件系统资源的利用率
                        System.out.println(" Usage = " + usePercent + "%");
                        break;
                    case 3:// TYPE_NETWORK ：网络
                        break;
                    case 4:// TYPE_RAM_DISK ：闪存
                        break;
                    case 5:// TYPE_CDROM ：光驱
                        break;
                    case 6:// TYPE_SWAP ：页面交换
                        break;
                }
                System.out.println(" DiskReads = " + usage.getDiskReads());
                System.out.println(" DiskWrites = " + usage.getDiskWrites());
            }
        } finally {
            shutdown();
        }
    }

    //网络信息
    //获取当前机器的正式域名
    public String getFQDN() {
        try {
            return InetAddress.getLocalHost().getCanonicalHostName();
        } catch (UnknownHostException e) {
            try {
                sigarInit(false);
                return sigar.getFQDN();
            } catch (SigarException ex) {
                return null;
            } finally {
                shutdown();
            }
        }
    }

    // 获取到当前机器的IP地址
    public String getDefaultIpAddress() throws UnknownHostException {
        sigarInit(false);
        String address = null;
        try {
            address = InetAddress.getLocalHost().getHostAddress();
            // 没有出现异常而正常当取到的IP时，如果取到的不是网卡循回地址时就返回
            // 否则再通过Sigar工具包中的方法来获取
            if (!NetFlags.LOOPBACK_ADDRESS.equals(address)) {
                return address;
            }
        } catch (UnknownHostException e) {
            throw new UnknownHostException("hostname not in DNS");
        }

        try {
            address = sigar.getNetInterfaceConfig().getAddress();
        } catch (SigarException e) {
            address = NetFlags.LOOPBACK_ADDRESS;
        } finally {
            shutdown();
        }
        return address;
    }

    //获取到当前机器的MAC地址
    /*
     * 如果存在多张网卡包括虚拟机的网卡，默认只取第一张网卡的MAC地址，如果要返回所有的网卡（包括物理的和虚拟的）则可以修改方法的返回类型为数组或Collection，
     * 通过在for循环里取到的多个MAC地址。
     */
    public String getMAC() {
        try {
            sigarInit(false);
            String[] ifaces = sigar.getNetInterfaceList();
            String hwaddr = null;
            for (String iface : ifaces) {
                NetInterfaceConfig cfg = sigar.getNetInterfaceConfig(iface);
                if (NetFlags.LOOPBACK_ADDRESS.equals(cfg.getAddress()) || (cfg.getFlags() & NetFlags.IFF_LOOPBACK) != 0 || NetFlags.NULL_HWADDR.equals(cfg.getHwaddr())) {
                    continue;
                }
                hwaddr = cfg.getHwaddr();
                break;
            }
            return !StringUtils.isEmpty(hwaddr) ? hwaddr : null;
        } catch (Exception e) {
            return null;
        } finally {
            if (!StringUtils.isEmpty(sigar)) {
                shutdown();
            }
        }
    }

    //获取网络流量等信息
    public void getNetIfList() throws Exception {
        try {
            sigarInit(false);
            String ifNames[] = sigar.getNetInterfaceList();
            for (String name : ifNames) {
                NetInterfaceConfig ifconfig = sigar.getNetInterfaceConfig(name);
                print("\nname = " + name);// 网络设备名
                print("Address = " + ifconfig.getAddress());// IP地址
                print("Netmask = " + ifconfig.getNetmask());// 子网掩码
                if ((ifconfig.getFlags() & 1L) <= 0L) {
                    print("!IFF_UP...skipping getNetInterfaceStat");
                    continue;
                }
                try {
                    NetInterfaceStat ifstat = sigar.getNetInterfaceStat(name);
                    print("RxPackets = " + ifstat.getRxPackets());// 接收的总包裹数
                    print("TxPackets = " + ifstat.getTxPackets());// 发送的总包裹数
                    print("RxBytes = " + ifstat.getRxBytes());// 接收到的总字节数
                    print("TxBytes = " + ifstat.getTxBytes());// 发送的总字节数
                    print("RxErrors = " + ifstat.getRxErrors());// 接收到的错误包数
                    print("TxErrors = " + ifstat.getTxErrors());// 发送数据包时的错误数
                    print("RxDropped = " + ifstat.getRxDropped());// 接收时丢弃的包数
                    print("TxDropped = " + ifstat.getTxDropped());// 发送时丢弃的包数
                } catch (SigarNotImplementedException ignored) {
                } catch (SigarException e) {
                    print(e.getMessage());
                }
            }
        } finally {
            shutdown();
        }
    } void print(String msg) {
        System.out.println(msg);
    }

    //其他的信息
    public void getEthernetInfo() {
        try {
            sigarInit(false);
            String[] ifaces = sigar.getNetInterfaceList();
            for (String iface : ifaces) {
                NetInterfaceConfig cfg = sigar.getNetInterfaceConfig(iface);
                if (NetFlags.LOOPBACK_ADDRESS.equals(cfg.getAddress()) || (cfg.getFlags() & NetFlags.IFF_LOOPBACK) != 0 || NetFlags.NULL_HWADDR.equals(cfg.getHwaddr())) {
                    continue;
                }
                System.out.println("cfg.getAddress() = " + cfg.getAddress());// IP地址
                System.out.println("cfg.getBroadcast() = " + cfg.getBroadcast());// 网关广播地址
                System.out.println("cfg.getHwaddr() = " + cfg.getHwaddr());// 网卡MAC地址
                System.out.println("cfg.getNetmask() = " + cfg.getNetmask());// 子网掩码
                System.out.println("cfg.getDescription() = " + cfg.getDescription());// 网卡描述信息
                System.out.println("cfg.getType() = " + cfg.getType());//
                System.out.println("cfg.getDestination() = " + cfg.getDestination());
                System.out.println("cfg.getFlags() = " + cfg.getFlags());//
                System.out.println("cfg.getMetric() = " + cfg.getMetric());
                System.out.println("cfg.getMtu() = " + cfg.getMtu());
                System.out.println("cfg.getName() = " + cfg.getName());
                System.out.println();
            }
        } catch (Exception e) {
            System.out.println("Error while creating GUID" + e);
        } finally {
            if (!StringUtils.isEmpty(sigar)) {
                shutdown();
            }
        }
    }

    public static void fillHeap(int num) throws InterruptedException {
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        for(int i=0; i < num; i++){
            // 延时1秒
            Thread.sleep(1000);
            byte[] bt = new byte[512*1024];
            System.out.println("===========当前时间:"+df.format(new Date())+"==============");
            printMemoryInfo();
        }
        // 触发垃圾回收
        System.gc();
    }

    private static void printMemoryInfo(){
        MemoryMXBean memory = ManagementFactory.getMemoryMXBean();
        MemoryUsage headMemory = memory.getHeapMemoryUsage();
        System.out.println("head堆:");
        System.out.println("\t初始(字节):"+headMemory.getInit());
        System.out.println("\t最大(上限)(字节):"+headMemory.getMax());
        System.out.println("\t当前(已使用)(字节):"+headMemory.getUsed());
        System.out.println("\t提交的内存(已申请)(字节):"+headMemory.getCommitted());
        System.out.println("\t使用率:"+headMemory.getUsed()*100/headMemory.getCommitted()+"%");

        System.out.println("non-head非堆:");
        MemoryUsage nonheadMemory = memory.getNonHeapMemoryUsage();
        System.out.println("\t初始(字节):"+nonheadMemory.getInit());
        System.out.println("\t最大(上限)(字节):"+nonheadMemory.getMax());
        System.out.println("\t当前(已使用)(字节):"+nonheadMemory.getUsed());
        System.out.println("\t提交的内存(已申请)(字节):"+nonheadMemory.getCommitted());
        System.out.println("\t使用率:"+nonheadMemory.getUsed()*100/nonheadMemory.getCommitted()+"%");
    }

}
